package com.jzr.netty.service;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.net.InetSocketAddress;

@Component
public class NettyServer implements Runnable {
    @Value("${netty.port}")
    private int port;

    @Autowired
    NettyServerHandler nettyServerHandler;

    private Logger log = LoggerFactory.getLogger(this.getClass());
    ServerBootstrap bootstrap = null;
    EventLoopGroup boss = null;
    EventLoopGroup worker = null;
    ChannelFuture future = null;

    public NettyServer(){
    }

    @PreDestroy
    public void stop() {
        log.info("netty stopping...");
        try {
            if (future != null) {
                future.channel().close().addListener(ChannelFutureListener.CLOSE);
                future.awaitUninterruptibly();
                future = null;
            }
            if (boss != null) {
                boss.shutdownGracefully().sync();
                boss = null;
            }
            if (worker != null) {
                worker.shutdownGracefully().sync();
                worker = null;
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
        log.info("netty stopped");
    }

    public void run() {
        try{
            log.info("netty on port:" + port + " starting...");
            bootstrap = new ServerBootstrap();
            boss = new NioEventLoopGroup();
            worker = new NioEventLoopGroup();

            bootstrap.group(boss,worker)
                    .option(ChannelOption.SO_BACKLOG,1024)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childOption(ChannelOption.SO_KEEPALIVE,true)
                    .channel(NioServerSocketChannel.class)
                    .localAddress(new InetSocketAddress(port))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new ObjectEncoder());
                            ch.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
                            ch.pipeline().addLast(nettyServerHandler);
                        }
                    });

            future = bootstrap.bind(port).sync();
            if(future.isSuccess()){
                log.info("netty - started");
            }

            // 等待服务端监听端口关闭
            future.channel().closeFuture().sync();
            future = null;
        }catch (Exception e){
            log.info("netty start exception---------------{}",e);
            e.printStackTrace();

        }finally {
            stop();
        }
    }
}